{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 线程池Cached模式设计实现 一"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 线程池项目"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  用户自己设置线程池的工作模式"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 模式类型：线程池支持两种工作模式：\n",
    "  - `MODE_FIXED`：固定数量的线程模式\n",
    "  - `MODE_CACHED`：线程数量可动态增长模式\n",
    "- 设置时机：所有set相关操作必须在调用`start()`方法之前完成，类比导弹发射前需要设置好所有参数\n",
    "- 接口设计：\n",
    "  - `setMode(PoolMode mode)`：设置线程池工作模式\n",
    "  - `setTaskQueMaxThreshHold(int threshhold)`：设置任务队列上限阈值\n",
    "- 防御性编程：需要防止用户在`start()`后修改配置，避免组件不稳定"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 返回Result机制设计"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 任务获取：\n",
    "  - 使用条件变量`notEmpty_.wait`等待任务队列非空\n",
    "  - 获取任务后通过`notFull_.notify_all()`通知可继续提交任务\n",
    "- 任务执行：\n",
    "  - 通过`task->exec()`执行任务\n",
    "  - 任务返回值通过`setVal`方法设置到`Result`对象\n",
    "- 结果获取：\n",
    "  - `Result::get()`返回`Any`类型结果\n",
    "  - 使用`cast_<T>()`模板方法转换为具体类型（如`cast_<uLong>()`）\n",
    "  - 示例：`uLong sum1 = res1.get().cast_<uLong>()`\n",
    "- 典型用法：\n",
    "- 生命周期管理：\n",
    "  - `Task`对象执行完毕后会被销毁\n",
    "  - 依赖于`Task`的`Result`对象也会随之失效\n",
    "  - 需要及时通过`get()`获取结果"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 用户设置线程池过程中问题"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "增加启动状态标记\n",
    "\n",
    "- 新增变量作用：用于记录线程池当前是否已启动，防止线程池启动后再次修改配置参数\n",
    "- 变量类型选择：建议使用布尔值表示线程池的启动状态（`true`表示已启动，`false`表示未启动）\n",
    "- 线程安全考虑：该状态变量可能在多线程环境下被访问，需要考虑线程安全问题"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "启动状态标记为原子类型\n",
    "\n",
    "- 原子类型必要性：当状态变量可能被多个线程访问时，应使用`std::atomic<bool>`保证操作的原子性\n",
    "- 单线程特例：如果确定状态变量只会在单个线程中使用，可以使用普通`bool`类型\n",
    "- 设计原则：线程池相关配置参数（如模式、阈值等）在启动后应禁止修改，状态变量是实现此约束的关键"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池清理\n",
    "\n",
    "- 清理触发条件：在CACHED模式下，当线程空闲时间超过60秒时需要回收多余线程\n",
    "- 实现位置：清理逻辑应实现在线程函数内部，通过定期检查条件触发\n",
    "- 资源管理：需要正确处理线程对象的生命周期，确保安全释放资源"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程函数定义\n",
    "\n",
    "- 基本流程：\n",
    "  - 获取任务队列锁\n",
    "  - 等待任务队列非空条件\n",
    "  - 取出任务并执行\n",
    "- 条件变量使用：\n",
    "  - 使用`notEmpty_`条件变量等待任务到来\n",
    "  - 使用`notFull_`条件变量通知任务队列有空位\n",
    "- 异常处理：需要考虑任务执行过程中的异常情况，保证线程不会意外终止\n",
    "- 典型用法：\n",
    "  - 先设置线程池模式（如MODE_CACHED）\n",
    "  - 调用`start()`方法启动线程池\n",
    "  - 通过`submitTask()`提交任务\n",
    "  - 通过`Result`对象获取任务执行结果"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "用户设置线程池过程中问题总结 \n",
    "\n",
    "- 线程安全变量：标识线程池是否正在执行的变量需要定义为原子类型（如`std::atomic`），避免多线程访问时的安全问题\n",
    "- 初始状态设置：构造函数中应将运行状态变量`isPoolRunning_`初始化为`false`，表示线程池初始未运行"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "增加检查运行状态方法\n",
    "\n",
    "- 状态修改时机：在`start()`方法中需要修改`isPoolRunning_`状态为`true`，表示线程池开始运行\n",
    "- 原子操作必要性：使用`std::atomic`可以确保状态变量的修改是线程安全的"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`set`方法中增加判断代码 \n",
    "\n",
    "- 前置条件检查：每个`set`方法开始都需要检查线程池是否已启动，已启动则不允许修改配置\n",
    "- 代码复用问题：直接在各个`set`方法中重复编写状态检查代码会导致维护困难"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "增加检查运行状态方法\n",
    "\n",
    "- 封装检查方法：应设计私有方法`checkRunningState()`统一处理运行状态检查\n",
    "- 访问控制：该方法应为`private`权限，仅限线程池内部使用\n",
    "- 方法命名规范：建议命名为`checkRunningState`，明确表达其功能意图\n",
    "- 线程函数实现：`threadFunc()`方法负责从任务队列消费任务，需要处理线程同步问题\n",
    "- 条件变量使用：通过`notEmpty_.wait()`实现任务队列非空时的线程等待"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "方法实现过程 \n",
    "\n",
    "- 任务执行机制：当线程从任务队列获取到任务后，会调用任务的`exec()`方法执行，而不是直接调用`run()`方法。通过`exec()`方法可以将任务返回值通过`setVal`方法传递给`Result`对象。\n",
    "- 线程通知机制：在全局范围内使用`notFull_.notify_all()`来通知所有等待的线程任务队列状态变化，这个操作应该在释放锁之后执行。\n",
    "- 线程构造：Thread类的构造函数接收ThreadFunc类型的函数对象，通过`std::thread(func_)`创建实际执行线程，实现线程对象与线程函数的绑定。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "统一判断变量的实现\n",
    "\n",
    "- 状态检查方法：`checkRunningState()`方法通过返回`isPoolRunning_`原子布尔变量来判断线程池运行状态。\n",
    "- 设计思想：将状态判断逻辑集中封装在`checkRunningState()`方法中，便于未来扩展更多状态变量的判断。\n",
    "- 实现细节：使用`std::atomic_bool`保证多线程环境下`isPoolRunning_`变量的原子性访问，避免数据竞争。\n",
    "- 核心成员：\n",
    "  - `threads_`：存储线程对象的`vector`容器，使用`unique_ptr`管理线程生命周期\n",
    "  - `taskQue_`：任务队列，存储`shared_ptr`包装的`Task`对象\n",
    "  - `taskQueMtx_`：互斥锁，保证任务队列线程安全\n",
    "  - `notFull_/notEmpty_`：条件变量，实现生产者-消费者模型\n",
    "  - `isPoolRunning_`：原子布尔变量，标识线程池运行状态"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池的状态管理\n",
    "\n",
    "- 线程池模式设置方法\n",
    "  - 状态检查机制: 通过`checkRunningState()`方法检查线程池是否运行，若已运行(`poolRunning_`为`true`)则直接`return`，防止运行中修改配置\n",
    "  - 模式设置限制: 只能在`start()`调用前设置`poolMode_`，构造函数中默认初始化为`MODE_FIXED`\n",
    "  - 线程安全设计: 使用互斥锁`taskQueMtx_`保护共享变量，避免多线程竞争\n",
    "\n",
    "\n",
    "- 任务队列阈值设置\n",
    "  - 阈值修改条件: 与`setMode`相同，运行状态下(`setTaskQueMaxThreshHold`)禁止修改`taskQueMaxThreshHold_`\n",
    "  - 参数验证: 需要检查传入的`threshold`值有效性，避免负值等非法输入\n",
    "  - 设计原则: 遵循\"初始化阶段可配置，运行阶段不可变\"的设计模式\n",
    "\n",
    "\n",
    "- 线程池启动机制\n",
    "  - 状态转换: `start()`方法将`isPoolRunning_`从`false`设为`true`，完成初始化到运行状态的转换\n",
    "  - 防御性编程: 所有配置方法(`setMode/setTaskQueMaxThreshHold`)都需要检查运行状态\n",
    "  - 错误预防: 构造函数中明确初始化所有状态变量，避免未定义行为\n",
    "\n",
    "\n",
    "- 任务提交接口设计\n",
    "  - 超时控制: 使用`wait_for`实现1秒提交超时机制，防止任务队列满时永久阻塞\n",
    "  - 条件变量: `notFull_`条件变量实现生产者-消费者模型，当`taskQue_.size() < taskQueMaxThreshHold_`时唤醒等待线程\n",
    "  - 锁机制: 采用`std::unique_lock`, `std::mutex`实现RAII风格的锁管理\n",
    "\n",
    "- 线程池使用示例\n",
    "  - 模式设置时机: 在`start(4)`调用前通过`setMode(PoolMode::MODE_CACHED)`配置工作模式\n",
    "  - 任务结果获取: 通过`Result`对象的`get()`方法获取`Any`类型结果，再使用`cast_`转换为具体类型(`uLong`)\n",
    "  - 生命周期管理: 任务对象(`std::shared_ptr<Task>`)与结果对象(`Result`)的生命周期自动管理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "submitTask中判断代码的封装\n",
    "\n",
    "- 线程池的`submitTask`方法实现 \n",
    "  - 任务队列满判断:\n",
    "    - 使用条件变量`notFull_`和`wait_for`方法实现1秒超时等待\n",
    "    - 条件判断：`taskQue_.size() < (size_t)taskQueMaxThreshHold_`\n",
    "    - 超时后输出错误信息并返回失败`Result`对象\n",
    "  - 任务添加流程:\n",
    "    - 成功获取锁后将任务放入队列：`taskQue_.emplace(sp)`\n",
    "    - 通知等待线程：`notEmpty_.notify_all()`\n",
    "    - 返回成功`Result`对象\n",
    "  - 线程安全保证:\n",
    "    - 使用`std::unique_lock<std::mutex>`保护任务队列\n",
    "    - 任务数量使用`std::atomic_int`保证线程安全\n",
    "  - 线程池模式选择:\n",
    "    - `Cached`模式：适合小而快的任务，任务处理紧急\n",
    "    - `Fixed`模式：适合耗时任务，避免线程过多影响系统性能\n",
    "  - 关键成员变量:\n",
    "    - `threads_`：线程列表，存储`std::unique_ptr<Thread>`\n",
    "    - `taskQue_`：任务队列，存储`std::shared_ptr<Task>`\n",
    "    - `taskSize_`：原子整型记录任务数量\n",
    "    - `taskQueMaxThreshHold_`：任务队列上限阈值\n",
    "    - `notFull_/notEmpty_`：条件变量控制队列状态\n",
    "  - 任务获取流程:\n",
    "    - 线程通过`notEmpty_.wait`等待任务\n",
    "    - 获取任务后从队列移除：`taskQue_.pop()`\n",
    "    - 原子递减任务计数：`taskSize--`\n",
    "    - 队列仍有任务时通知其他线程：`notEmpty_.notify_all()`\n",
    "  - 空闲线程管理:\n",
    "    - Cached模式下需记录空闲线程数量`idleThreadSize`\n",
    "    - 空闲超时(60s)的线程应被回收\n",
    "    - 使用原子整型保证线程安全\n",
    "  - 构造函数初始化:\n",
    "    - 初始空闲线程数为`0`：`idleThreadSize_(0)`\n",
    "    - 默认模式为Fixed：`poolMode_(PoolMode::MODE_FIXED)`\n",
    "    - 运行状态初始为`false`：`isPoolRunning_(false)`\n",
    "  - 线程启动流程:\n",
    "    - `start()`方法设置运行状态为`true`\n",
    "    - 创建并启动指定数量的线程\n",
    "    - 每启动一个线程递增空闲计数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程执行任务功能的实现 \n",
    "\n",
    "- 线程池初始化\n",
    "  - 运行状态设置: 通过`isPoolRunning_ = true`设置线程池为运行状态\n",
    "  - 线程创建过程:\n",
    "    - 记录初始线程数量`initThreadSize_ = initThreadSize`\n",
    "    - 使用循环创建指定数量的线程对象\n",
    "    - 每个线程绑定`ThreadPool::threadFunc`函数\n",
    "    - 将线程对象存入`threads_`容器\n",
    "  - 线程启动: 遍历线程容器调用`start()`方法启动所有线程\n",
    "- 线程函数执行流程\n",
    "  - 阻塞等待机制:\n",
    "    - 线程在没有任务时阻塞在条件变量`notEmpty_`上\n",
    "    - 使用wait方法配合谓词判断`taskQue_.size() > 0`\n",
    "  - 任务获取过程:\n",
    "    - 获取任务前需要先获取互斥锁`taskQueMtx_`\n",
    "    - 从任务队列头部取出任务`task = taskQue_.front()`\n",
    "    - 执行队列弹出操作`taskQue_.pop()`\n",
    "    - 更新任务计数`taskSize_--`\n",
    "  - 通知机制:\n",
    "    - 如果队列仍有任务，调用`notEmpty_.notify_all()`通知其他线程\n",
    "    - 取出任务后调用`notFull_.notify_all()`允许继续提交任务\n",
    "- 线程状态管理\n",
    "  - 空闲线程计数:\n",
    "    - 初始化时空闲线程数为0\n",
    "    - 启动线程池时通过`idleThreadSize_++`增加计数\n",
    "    - 线程获取任务时`idleThreadSize_--`\n",
    "    - 任务完成后`idleThreadSize_++`\n",
    "  - 线程工作流程:\n",
    "    - 空闲线程被唤醒后立即变为非空闲状态\n",
    "    - 执行任务期间保持非空闲状态\n",
    "    - 任务完成后恢复空闲状态\n",
    "- 任务提交逻辑\n",
    "  - 任务队列检查:\n",
    "    - 使用`wait_for`设置1秒超时等待队列有空位\n",
    "    - 谓词条件`taskQue_.size() < taskQueMaxThreshHold_`\n",
    "  - 任务添加过程:\n",
    "    - 将任务对象放入队列`taskQue_.emplace(sp)`\n",
    "    - 更新任务计数`taskSize_++`\n",
    "    - 通知等待线程`notEmpty_.notify_all()`\n",
    "  - 异常处理:\n",
    "    - 超时后返回失败结果`Result(sp, false)`\n",
    "    - 输出错误信息\"task queue is full, submit task fail.\"\n",
    "- Cached模式特殊处理\n",
    "  - 新线程创建条件:\n",
    "    - 模式为`PoolMode::CACHED`\n",
    "    - 任务数量大于空闲线程数`taskSize_ > idleThreadSize_`\n",
    "  - 创建限制:\n",
    "    - 避免无限制创建线程导致系统崩溃\n",
    "    - 适用于小而快的任务场景\n",
    "  - 线程回收机制:\n",
    "    - 空闲超过60秒的线程应被结束回收\n",
    "    - 通过定时检查实现线程数量动态调整"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "任务/线程数量上限阈值设置\n",
    "\n",
    "- 线程池阈值控制机制\n",
    "   - 线程数量阈值：新增成员变量 `threadSizeThreshHold_`，用于在 CACHED 模式下限制最大线程数，防止资源耗尽。\n",
    "   - 任务队列阈值：通过 `taskQueMaxThreshHold_` 限制队列长度，搭配条件变量 `notFull_` 实现队列满时的阻塞控制。\n",
    "   - 模式区别：\n",
    "       * MODE_FIXED：线程数量固定为 `initThreadSize_`。\n",
    "       * MODE_CACHED：按需创建线程，但不超过 `threadSizeThreshHold_`。\n",
    "\n",
    "- 阈值设置实现细节\n",
    "   - 默认值：\n",
    "       * `TASK_MAX_THRESHHOLD = 4`（测试环境示例）\n",
    "       * `THREAD_MAX_THRESHHOLD = 200`\n",
    "   - 动态配置：\n",
    "       * 提供 `setThreadSizeThreshHold()`，允许根据服务器配置（例如 8G vs 128G 内存）调整阈值。\n",
    "\n",
    "- 阈值校验逻辑\n",
    "   - 状态检查：调用 `checkRunningState()`，确保线程池尚未启动；运行期间修改阈值会产生不可预期行为。\n",
    "   - 模式限制：仅 `MODE_CACHED` 需要设置线程数量阈值；`MODE_FIXED` 忽略该设置。\n",
    "   - 降级处理：达到阈值上限时返回错误提示，而不是导致崩溃，以保障用户体验。\n",
    "\n",
    "- 任务提交流程优化\n",
    "   - 阻塞控制：\n",
    "       * 使用 `wait_for` 将任务提交等待时间限制为 1 秒。\n",
    "       * 超时返回 `Result(taskPtr, false)`，提示提交失败。\n",
    "   - 动态扩容：\n",
    "       * 在 `MODE_CACHED` 下，当 `taskSize_ > idleThreadSize_` 时考虑创建新线程。\n",
    "       * 同时要求 `threads_.size() < threadSizeThreshHold_`。\n",
    "   - 线程通信：\n",
    "       * 任务入队后调用 `notEmpty_.notify_all()` 唤醒工作线程。\n",
    "       * 使用 `taskQueMtx_` 保护队列操作的线程安全。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池线程数量管理\n",
    "\n",
    "- 线程数量上限阈值\n",
    "  - 阈值作用：表示线程池中线程数量的上限值，实际创建的线程数量可能少于这个阈值\n",
    "  - 动态特性：线程数量会随时改变，不能使用普通整型变量\n",
    "  - 实现方式：必须使用原子整型`std::atomic_int`来保证线程安全\n",
    "  - 分类原则：\n",
    "    - 线程相关变量（线程列表、当前线程数、空闲线程数）放在一起\n",
    "    - 任务相关变量（任务队列、任务数量）放在一起\n",
    "    - 线程通信变量（互斥锁、条件变量）放在一起\n",
    "    - 线程池状态变量（运行状态、工作模式）放在一起\n",
    "- 关键成员变量\n",
    "  - `curThreadSize_`：记录当前线程池中线程的总数量，类型为`std::atomic_int`\n",
    "  - `idleThreadSize_`：记录空闲线程的数量，同样使用原子整型\n",
    "  - `threadSizeThreshHold_`：线程数量上限阈值，普通整型\n",
    "  - 初始化值：构造函数中将`curThreadSize_`初始化为`0`\n",
    "  - 启动设置：在`start()`方法中，`curThreadSize_`被设置为初始线程数量`initThreadSize_`\n",
    "- 线程数量控制逻辑\n",
    "  - 创建限制：在CACHED模式下创建新线程时，必须检查curThreadSize_是否小于`threadSizeThreshHold_`\n",
    "  - 资源紧张判断：当线程数量达到上限阈值时，表示系统资源已相当紧张，不能再创建新线程\n",
    "  - 动态调整：在CACHED模式下，当任务数量(`taskSize_`)大于空闲线程数量(`idleThreadSize_`)且当前线程数(`curThreadSize_`)未达上限时，可以创建新线程"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 线程池任务提交与线程创建机制"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "任务提交失败处理\n",
    "\n",
    "- 队列满判定条件：当`taskQue_.size() >= taskQueMaxThreshHold_`时，通过`notFull_.wait_for`等待1秒后仍不满足条件则判定失败\n",
    "- 失败反馈机制：返回包含`false`状态的`Result`对象，并输出错误信息\"task queue is full, submit task fail.\"\n",
    "- 资源释放注意：不能直接返回`task->getResult()`，因为任务对象可能在执行完成后被析构"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "任务成功入队处理\n",
    "\n",
    "- 入队操作：使用`taskQue_.emplace(sp)`将任务放入队列，并递增`taskSize_`计数器\n",
    "- 线程通知机制：通过`notEmpty_.notify_all()`唤醒等待线程执行任务\n",
    "- CACHED模式特性：专门处理小而快的紧急任务，需动态调整线程数量"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "CACHED模式线程创建条件\n",
    "\n",
    "- 三重判断标准：\n",
    "  - 当前模式为`PoolMode::MODE_CACHED`\n",
    "  - 任务数量大于空闲线程数(`taskSize_ > idleThreadSize_`)\n",
    "  - 当前线程总数小于阈值(`curThreadSize_ < threadSizeThreshHold_`)\n",
    "- 线程创建过程：\n",
    "  - 使用`std::make_unique<Thread>`创建线程对象\n",
    "  - 通过`std::bind`绑定`ThreadPool::threadFunc`成员方法\n",
    "  - 将线程对象移入`threads_`容器管理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池初始化流程\n",
    "\n",
    "- 状态设置：先将`isPoolRunning_`置为`true`标记运行状态\n",
    "- 线程数量记录：初始化时保存`initThreadSize_`和`curThreadSize_`\n",
    "- 线程创建规范：\n",
    "  - 每个线程绑定到`threadFunc`成员函数\n",
    "  - 使用`std::unique_ptr`管理线程对象\n",
    "  - 启动后递增`idleThreadSize_`计数器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池核心数据结构\n",
    "\n",
    "- 线程管理：\n",
    "  - `threads_`：存储线程对象的容器\n",
    "  - `initThreadSize_/curThreadSize_`：初始和当前线程数\n",
    "  - `threadSizeThreshHold_`：线程数量上限阈值\n",
    "- 任务管理：\n",
    "  - `taskQue_`：任务队列容器\n",
    "  - `taskSize_/taskQueMaxThreshHold_`：任务数量和上限\n",
    "  - `taskQueMtx_`：保证队列线程安全的互斥锁\n",
    "- 同步机制：\n",
    "  - `notFull_/notEmpty_`：条件变量实现生产者-消费者模型\n",
    "  - `idleThreadSize_`：空闲线程计数器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 线程池Cached模式设计实现 二"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 线程安全"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 线程数量表示：可以使用`vector`对象的`size`来表示线程数量，但`vector`本身不是线程安全的\n",
    "- 线程安全设计：\n",
    "  - 在多线程环境中，线程数量会动态增减，应该使用`atomic`类型\n",
    "  - 实际实现中使用`atomic_int`原子整型变量来记录当前线程数量\n",
    "  - 原子变量的加减操作都是线程安全的"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 任务提交处理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "任务队列满处理\n",
    "\n",
    "- 等待机制：使用`wait_for`等待1秒，如果条件仍未满足则返回失败\n",
    "- 失败处理：\n",
    "  - 输出\"task queue is full, submit task fail.\"错误信息\n",
    "  - 返回包含`false`标志的`Result`对象\n",
    "  - 不能直接返回`task->getResult()`，因为`task`对象可能已被析构"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "任务入队处理\n",
    "\n",
    "- 入队操作：\n",
    "  - 使用`emplace`将任务放入任务队列\n",
    "  - 原子递增`taskSize_`计数器\n",
    "- 线程通知：\n",
    "  - 使用`notify_all`通知`notEmpty_`条件变量\n",
    "  - 唤醒等待线程执行新任务"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`CACHED` 模式处理\n",
    "\n",
    "- 创建条件：\n",
    "  - 当前模式为 `MODE_CACHED`\n",
    "  - 任务数量大于空闲线程数量（`taskSize_ > idleThreadSize_`）\n",
    "  - 当前线程数小于阈值（`curThreadSize_ < threadSizeThreshHold_`）\n",
    "- 线程创建：\n",
    "  - 使用 `make_unique` 创建新线程对象\n",
    "  - 绑定 `threadFunc` 作为线程函数\n",
    "  - 将线程对象加入 `threads_` 列表\n",
    "  - 原子递增 `curThreadSize_` 计数器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "结果返回\n",
    "\n",
    "- 成功返回：构造并返回包含任务指针的 `Result` 对象\n",
    "- 线程池启动：\n",
    "  - 设置 `isPoolRunning_` 为 `true`\n",
    "  - 记录初始线程数量 `initThreadSize_`\n",
    "  - 创建指定数量的线程对象\n",
    "  - 每个线程绑定 `threadFunc` 函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 线程函数定义"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程函数概述\n",
    "\n",
    "- 基本结构：线程函数 `threadFunc` 是线程池中所有线程执行的核心函数，负责从任务队列消费任务\n",
    "- 生命周期：线程创建时绑定该函数，执行过程中会持续检查任务队列状态\n",
    "- 调试信息：函数首尾会输出线程 `ID` 标识执行过程，格式为 `begin/end threadFunc tid:[ID]`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程任务调度 \n",
    "\n",
    "- 锁机制：使用 `unique_lock<mutex>` 保护任务队列，确保线程安全访问\n",
    "- 条件变量：通过 `notEmpty_.wait()` 实现阻塞等待，当 `taskQue_.size() > 0` 时唤醒线程\n",
    "- 任务处理：获取任务后执行 `task->exec()`，并动态调整 `idleThreadSize_` 计数\n",
    "- 级联通知：任务取出后通过 `notFull_.notify_all()` 允许继续提交新任务"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池启动与线程创建 \n",
    "\n",
    "- 启动流程：\n",
    "  - 设置运行状态 `isPoolRunning_ = true`\n",
    "  - 记录初始线程数 `initThreadSize_` 和当前线程数 `curThreadSize_`\n",
    "  - 使用 `std::make_unique<Thread>` 创建线程对象\n",
    "- 线程绑定：通过 `std::bind(&ThreadPool::threadFunc, this)` 将线程函数绑定到线程对象\n",
    "- 线程启动：调用 `threads_[i]->start()` 启动所有线程，初始化 `idleThreadSize_` 计数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程回收策略\n",
    "\n",
    "- 回收条件：在 `CACHED` 模式下，超过 `initThreadSize_` 的线程空闲超过 60 秒需回收\n",
    "- 时间记录：使用 `std::chrono::high_resolution_clock` 记录线程最后执行时间\n",
    "- 设计原则：保持初始线程数不变，动态回收多余线程以节省资源\n",
    "- 实现要点：需要比较当前时间与最后执行时间的差值判断是否超时"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程执行时间记录与更新\n",
    "\n",
    "\n",
    "- 初始记录：线程进入函数时记录 `lastTime` 时间戳\n",
    "- 更新时间：在任务执行完成后立即更新时间戳\n",
    "- 精度选择：采用 C++11 的 `high_resolution_clock` 而非 C 语言 `time` 函数\n",
    "- 设计意义：准确记录线程从空闲到再次执行的时间间隔"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "条件变量与等待状态\n",
    "\n",
    "- 等待方式：提供 `wait`/`wait_for`/`wait_until` 三种阻塞方法\n",
    "- 返回值类型：`cv_status` 枚举包含 `no_timeout` 和 `timeout` 两种状态\n",
    "- 超时控制：`wait_for` 可设置最大阻塞时长（如 1 秒）\n",
    "- 实现原理：底层通过 `_Cnd_wait` 系统调用实现线程挂起"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "超时返回与任务待执行区分\n",
    "\n",
    "- 轮询机制：在 `CACHED` 模式下每 1 秒检查一次任务队列状态\n",
    "- 状态判断：通过 `std::cv_status::timeout` 区分超时返回与条件满足\n",
    "- 锁管理：等待期间保持锁的持有，避免竞态条件\n",
    "- 性能权衡：缩短检查间隔提高响应速度，但增加 `CPU` 开销"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "命名空间与作用域\n",
    "\n",
    "- 完整限定：必须使用 `std::cv_status` 而非简写 `cv_status`\n",
    "- 错误处理：缺少命名空间会导致 `\"作用域名称无效\"` 编译错误\n",
    "- 类型安全：`enum class` 提供强类型检查，避免隐式转换"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "开发规范与命名空间使用\n",
    "\n",
    "- 禁止规范：生产代码禁止使用 `using namespace` 简化写法\n",
    "- 冲突预防：显式命名空间可避免全局名称污染\n",
    "- 教学差异：教学示例为简化可能使用 `using`，但实际开发需严格限定\n",
    "- 标准库引用：所有 `STD` 组件必须带 `std::` 前缀（如 `std::mutex`）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 超时返回处理 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 禁止规范：生产代码禁止使用 `using namespace` 简化写法\n",
    "- 冲突预防：显式命名空间可避免全局名称污染\n",
    "- 教学差异：教学示例为简化可能使用 `using`，但实际开发需严格限定\n",
    "- 标准库引用：所有 `STD` 组件必须带 `std::` 前缀（如 `std::mutex`）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 时间计算 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "时间点获取\n",
    "\n",
    "- 时钟类型选择：使用 `std::chrono::high_resolution_clock` 或 `std::chrono::steady_clock` 获取当前时间点，返回值为 `time_point` 类型。\n",
    "- 时间单位灵活性：C++11 的 `chrono` 库支持秒、毫秒、微秒等单位的自由转换，通过模板参数实现。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "持续时间计算\n",
    "\n",
    "- 差值转换方法：使用 `std::chrono::duration_cast` 将时间差值转换为指定单位（如秒），例如：\n",
    "- 工具链提示问题：模板代码在编写阶段可能出现 `IDE` 误报（红色波浪线），实际编译时可能正常通过，需通过编译结果验证正确性。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程回收实现\n",
    "\n",
    "- 回收条件判断：通过 `dur.count() >= THREAD_MAX_IDLE_TIME` 判断是否达到最大空闲时间（60 秒）。\n",
    "- 常量定义规范：避免魔法数字，应定义常量 `THREAD_MAX_IDLE_TIME` 并注明单位为秒。\n",
    "- 线程回收操作：满足条件时需执行线程退出前的资源清理工作，包括锁释放和线程对象析构。\n",
    "- 模式切换接口：通过 `setMode(PoolMode mode)` 方法可动态切换线程池工作模式（如 `CACHED` 模式）。\n",
    "- 阈值配置方法：提供 `setThreadSizeThreshHold` 等方法设置线程数量和任务队列的阈值参数。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 线程数量相关变量的值修改 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 线程列表管理:\n",
    "  - 使用 `std::vector<std::unique_ptr<Thread>> threads_` 存储线程对象\n",
    "  - 线程结束时需要从该列表中移除对应线程对象\n",
    "- 关键计数器:\n",
    "  - `initThreadSize_`：初始线程数量（默认 4 个）\n",
    "  - `threadSizeThreshHold_`：线程数量上限阈值\n",
    "  - `curThreadSize_`：当前线程总数（原子变量）\n",
    "  - `idleThreadSize_`：空闲线程数（原子变量）\n",
    "- 任务队列相关:\n",
    "  - `taskQue_`：存储任务的队列\n",
    "  - `taskSize_`：当前任务数量（原子变量）\n",
    "  - `taskQueMaxThreshHold_`：任务队列上限阈值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Cached` 模式线程回收机制\n",
    "\n",
    "- 触发条件:\n",
    "  - 仅当 `poolMode_ == PoolMode::MODE_CACHED` 时生效\n",
    "  - 线程空闲时间超过`THREAD_MAX_IDLE_TIME`（60 秒）\n",
    "  - 当前线程数需大于初始线程数（`curThreadSize_ > initThreadSize_`）\n",
    "- 实现方式:\n",
    "  - 使用条件变量 `notEmpty_.wait_for(lock, std::chrono::seconds(1))` 进行超时检测\n",
    "  - 计算时间差：`std::chrono::duration_cast<std::chrono::seconds>(now - lastTime)`\n",
    "  - 当 `dur.count() >= 60` 时触发回收\n",
    "- 回收步骤:\n",
    "  - 修改线程数量计数器\n",
    "  - 从 `threads_` 容器中删除对应线程对象\n",
    "  - 确保最终线程数不低于 `initThreadSize_`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程安全控制\n",
    "\n",
    "- 互斥锁:\n",
    "  - 使用 `std::mutex taskQueMtx_` 保护任务队列操作\n",
    "- 条件变量:\n",
    "  - `notFull_`：表示任务队列未满\n",
    "  - `notEmpty_`：用于线程等待任务（含超时机制）\n",
    "- 原子操作:\n",
    "  - 对 `curThreadSize_`、`idleThreadSize_` 等计数器使用 `std::atomic_int`\n",
    "  - 确保多线程环境下计数的准确性"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程回收注意事项\n",
    "\n",
    "- 最小线程保持:\n",
    "  - 必须维持至少 `initThreadSize_` 数量的线程\n",
    "  - 防止长时间无任务时线程池被完全清空\n",
    "- 容器操作难点:\n",
    "  - 线程函数中难以直接匹配和删除自身线程对象\n",
    "  - 需要设计特殊机制识别待删除线程\n",
    "- 日志记录建议:\n",
    "  - 在关键操作点添加日志打印\n",
    "  - 便于调试线程创建/回收过程"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 线程对象删除问题"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`CACHED` 模式下的线程回收机制\n",
    "\n",
    "- 回收条件：\n",
    "  - 空闲时间超过 60 秒（`THREAD_MAX_IDLE_TIME`）\n",
    "  - 当前线程数大于初始线程数（`curThreadSize_ > initThreadSize_`）\n",
    "- 回收过程：\n",
    "  - 记录线程数量相关变量的修改\n",
    "  - 从线程列表容器中删除对应线程对象\n",
    "  - 线程函数通过 `return` 自然结束线程生命周期"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程对象映射关系设计\n",
    "\n",
    "- 关键数据结构：\n",
    "  - `std::vector<std::unique_ptr<Thread>> threads_`：存储线程对象的容器\n",
    "  - `std::atomic_int curThreadSize_`：实时记录线程总数\n",
    "- 映射关系建立：\n",
    "  - 通过`std::this_thread::get_id()`获取当前线程 `ID`\n",
    "  - 需要设计线程 `ID` 到线程对象的映射表\n",
    "  - 线程函数结束时需同步更新容器和计数器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程函数执行流程\n",
    "\n",
    "- 核心逻辑：\n",
    "  - 使用`std::unique_lock`保证任务队列线程安全\n",
    "  - 条件变量`notEmpty_.wait_for`实现超时检测（1 秒间隔）\n",
    "  - 时间差计算：`std::chrono::duration_cast(now - lastTime)`\n",
    "- 设计要点：\n",
    "  - 需要区分超时返回和有任务返回两种情况\n",
    "  - 线程最后一次执行时间记录（`lastTime`变量）\n",
    "  - `CACHED` 模式下动态线程数量管理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池常量配置\n",
    "\n",
    "- 关键参数：\n",
    "  - `TASK_MAX_THRESHHOLD = 4`：任务队列上限\n",
    "  - `THREAD_MAX_THRESHHOLD = 10`：最大线程数\n",
    "  - `THREAD_MAX_IDLE_TIME = 60`：线程最大空闲时间（秒）\n",
    "- 设计原则：\n",
    "  - 初始线程数默认为 4（`initThreadSize = 4`）\n",
    "  - 通过`setMode`方法切换 `POOL` 模式\n",
    "  - 阈值参数应通过专用接口设置保证线程安全"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 线程 `ID` 保存"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程 `ID` 的必要性\n",
    "\n",
    "- `Cached` 模式必备：在动态增长的线程池模式（`MODE_CACHED`）中，每个线程对象都需要保存唯一的线程 `ID` 用于管理\n",
    "- 线程标识作用：`ID` 用于区分不同线程对象，是线程池进行线程回收和管理的基础标识\n",
    "\n",
    "线程 `ID` 的生成方式\n",
    "\n",
    "\n",
    "- 静态计数器方案：使用静态成员变量 `static int generateId_` 作为 `ID` 生成器\n",
    "- 局部范围设计：每个线程对象在构造函数中获取当前 `ID` 值后，生成器自增\n",
    "- 简单实现原则：采用普通 `int` 类型而非无符号类型，实际开发中可根据需求调整数值范围\n",
    "\n",
    "线程 `ID` 的初始化\n",
    "\n",
    "- 初始值设置：静态成员变量 `generateId_` 初始化为 0\n",
    "- 初始化位置：在类外全局范围进行初始化（`cpp` 文件中）\n",
    "- 线程创建时机：所有线程创建都在用户调用 `start()` 或 `submitTask()` 时完成\n",
    "\n",
    "线程 `ID` 的获取方法\n",
    "\n",
    "- 封装获取接口：提供 `int getId() const` 方法获取线程 `ID`\n",
    "- 实现隐藏原则：将具体实现放在 `cpp` 文件而非头文件，避免暴露实现细节\n",
    "- 返回类型选择：使用有符号 `int` 而非无符号类型，保持设计灵活性\n",
    "\n",
    "线程 `ID` 的赋值过程\n",
    "\n",
    "- 构造时赋值：在 `Thread` 构造函数中通过 `threadId_(generateId_++)` 完成 `ID` 分配\n",
    "- 静态变量特性：`generateId_` 作为类静态成员，生命周期等同于全局变量\n",
    "- 线程安全考虑：当前实现假设线程创建都在单线程环境下完成（用户调用 `start` 时）\n",
    "- 自增操作：采用后置 `++` 确保先使用当前值再自增，保证 `ID` 唯一性"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 任务队列类型修改"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 容器选择：将线程列表从 `vector` 改为 `unordered_map`，键为线程 `ID`（整型），值为线程对象指针\n",
    "- 原因说明：\n",
    "  - 不需要对线程 `ID` 进行排序，因此使用无序容器更高效\n",
    "  - 便于通过线程 `ID` 直接删除对应的 `thread` 对象\n",
    "  - 键值对结构：`int → std::unique_ptr<Thread>`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 线程池项目代码修改"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`start` 函数修改\n",
    "\n",
    "- 线程创建流程：\n",
    "  - 创建线程对象时获取线程 `ID`：`int threadId = ptr->getId()`\n",
    "  - 使用 `emplace` 插入 `unordered_map`：`threads_.emplace(threadId, std::move(ptr))`\n",
    "  - 启动线程：`threads_[i]->start()`\n",
    "- 资源管理：\n",
    "  - 使用 `std::unique_ptr` 管理线程对象资源\n",
    "  - 通过 `std::move` 进行资源转移\n",
    "\n",
    "`submitTask` 函数修改\n",
    "\n",
    "- `CACHED` 模式处理：\n",
    "  - 当任务数大于空闲线程数且当前线程数小于阈值时创建新线程\n",
    "  - 创建方式与 `start` 函数一致：获取 `ID → emplace` 插入 `map`\n",
    "- 线程通信：\n",
    "  - 使用 `condition_variable` 进行任务队列状态通知\n",
    "  - `notEmpty_.notify_all()` 通知有新任务加入\n",
    "\n",
    "线程函数修改\n",
    "\n",
    "- 关键修改点：\n",
    "  - 需要为线程函数添加 `thread ID` 参数\n",
    "  - 通过 `ID` 可以定位具体的线程对象\n",
    "  - 修改涉及线程创建和管理的所有相关代码"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 线程池实现关键点"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程函数参数绑定\n",
    "- 参数占位符必要性：当线程函数需要参数时，在 `std::bind` 中必须使用 `std::placeholders` 为参数预留位置\n",
    "- 绑定方式修正：原代码 `std::bind(&ThreadPool::threadFunc, this)` 需改为 `std::bind(&ThreadPool::threadFunc, this, std::placeholders::_1)`\n",
    "- 线程 `ID` 传递：通过占位符将线程 `ID` 作为参数传递给 `threadFunc` 函数\n",
    "\n",
    "\n",
    "\n",
    "线程回收机制\n",
    "- `CACHED` 模式特性：\n",
    "  - 允许创建超过初始线程数的临时线程\n",
    "  - 空闲时间超过`THREAD_MAX_IDLE_TIME`(60 秒) 的额外线程会被回收\n",
    "- 空闲检测实现：\n",
    "  - 使用 `std::cv_status::timeout` 判断条件变量等待结果\n",
    "  - 通过 `high_resolution_clock` 计算线程空闲时长\n",
    "  - 当 `dur.count() >= THREAD_MAX_IDLE_TIME` 且当前线程数大于初始值时触发回收\n",
    "\n",
    "\n",
    "线程池启动流程\n",
    "- 状态设置：\n",
    "  - `isPoolRunning_ = true` 标记线程池运行状态\n",
    "  - 记录初始线程数 `initThreadSize_` 和当前线程数 `curThreadSize_`\n",
    "- 线程创建：\n",
    "  - 使用 `make_unique<Thread>` 创建线程对象\n",
    "  - 通过 `emplace` 将线程 `ID` 与线程对象存入 `map`\n",
    "- 线程启动：\n",
    "  - 遍历线程容器调用 `start()` 方法\n",
    "  - `idleThreadSize_` 计数器记录初始空闲线程数\n",
    "\n",
    "\n",
    "任务提交处理\n",
    "- 紧急任务处理：\n",
    "  - 当任务队列大小超过阈值且为 `CACHED` 模式时\n",
    "  - 满足 `idleThreadSize_ == 0 && curThreadSize_ < threadSizeThreshHold_` 条件时创建新线程\n",
    "- 线程创建参数：\n",
    "  - 使用 `std::placeholders::_1` 为线程函数预留参数位置\n",
    "  - 新线程 `ID` 通过 `ptr->getId()` 获取并存入线程 `map`\n",
    "  - `curThreadSize_` 计数器递增"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 执行任务时传参数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程函数参数传递机制\n",
    "\n",
    "\n",
    "- 参数绑定机制：通过 `std::bind` 将线程函数与参数绑定，需要明确指定参数传递方式\n",
    "- 线程 `ID` 传递：线程函数 `threadFunc` 需要接收线程 `ID` 作为参数，用于标识和管理线程\n",
    "- 条件变量超时处理：使用 `wait_for` 实现超时返回检测，通过 `cv_status::timeout` 判断超时情况\n",
    "\n",
    "线程池初始化实现\n",
    "\n",
    "- 线程创建流程：\n",
    "  - 设置 `isPoolRunning_` 状态为 `true`\n",
    "  - 记录初始线程数 `initThreadSize_` 和当前线程数 `curThreadSize_`\n",
    "  - 使用 `make_unique` 创建线程对象并绑定 `threadFunc`\n",
    "- 线程存储结构：将线程对象存入 `threads_` 容器，`key` 为 `threadId`\n",
    "- 线程启动方式：调用 `start()` 方法启动所有线程，并更新 `idleThreadSize_`\n",
    "\n",
    "线程函数实现细节\n",
    "\n",
    "- 参数传递验证：通过 `start()` 方法验证线程函数参数传递正确性\n",
    "- 线程分离设置：使用 `t.detach()` 实现线程分离，避免资源泄漏\n",
    "- 任务执行时机：当 `taskQue_` 不为空时立即执行任务，否则等待 1 秒超时\n",
    "\n",
    "线程回收机制\n",
    "\n",
    "- 空闲时间检测：通过 `high_resolution_clock` 记录最后任务执行时间\n",
    "- 线程回收条件：\n",
    "  - 空闲时间超过 `THREAD_MAX_IDLE_TIME` (60 秒)\n",
    "  - 当前线程数大于初始线程数\n",
    "- 回收操作：从 `threads_` 容器中移除对应 `threadId` 的线程对象\n",
    "\n",
    "线程类实现\n",
    "\n",
    "- 线程 `ID` 生成：使用静态变量 `generateId_` 自动分配唯一 `ID`\n",
    "- 线程启动实现：\n",
    "  - 创建 `std::thread` 对象并传入函数对象及 `threadId_`\n",
    "  - 调用 `detach()` 方法设置分离线程\n",
    "- 参数传递修正：需要确保 `threadFunc` 接收的 `threadId` 参数正确传递"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用 `map` 的相关处理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池任务提交逻辑\n",
    "\n",
    "- 任务队列操作: 使用 `taskQue_.emplace(sp)` 将任务放入队列，并通过 `taskSize_++` 记录任务数量增长\n",
    "- 线程唤醒机制: 当新任务加入后，通过 `notEmpty_.notify_all()` 唤醒等待在条件变量上的线程\n",
    "- `CACHED` 模式处理:\n",
    "  - 当模式为 `PoolMode::MODE_CACHED`\n",
    "  - 且当前任务数大于空闲线程数（`taskSize_ > idleThreadSize_`）\n",
    "  - 且当前线程数小于阈值（`curThreadSize_ < threadSizeThreshHold_`）时\n",
    "  - 会创建新线程执行任务\n",
    "\n",
    "线程池启动实现\n",
    "\n",
    "- 状态设置: 首先将 `isPoolRunning_` 设为 `true` 标记线程池运行状态\n",
    "- 线程初始化:\n",
    "  - 记录初始线程数到 `initThreadSize_` 和 `curThreadSize_`\n",
    "  - 使用 `std::make_unique<Thread>` 创建线程对象\n",
    "  - 通过 `std::bind` 绑定线程函数 `ThreadPool::threadFunc`\n",
    "- 线程存储变更:\n",
    "  - 从 `vector` 改为 `map` 结构存储线程\n",
    "  - 使用 `threads_.emplace(threadId, std::move(ptr))` 插入线程\n",
    "  - 需要修改所有使用到线程容器的地方\n",
    "\n",
    "线程启动与错误处理\n",
    "\n",
    "- 线程启动流程:\n",
    "  - 遍历初始线程数 `initThreadSize_`\n",
    "  - 调用 `threads_[i]->start()` 启动每个线程\n",
    "  - 通过 `idleThreadSize_++` 记录空闲线程数\n",
    "- 常见错误:\n",
    "  - 类型转换错误：`\"Thread::Thread(Thread::ThreadFunc)\"` 无法将参数从 `\"std::_Binder\"` 类型转换\n",
    "  - 主要由于线程函数绑定方式与线程类构造函数参数不匹配导致\n",
    "  - 需要检查 `std::bind` 绑定结果与线程构造函数要求的参数类型是否一致\n",
    "\n",
    "线程函数实现\n",
    "\n",
    "- 线程生命周期: 线程函数返回即意味着线程结束\n",
    "- 任务消费逻辑:\n",
    "  - 使用无限循环持续从任务队列获取任务\n",
    "  - 记录最后活动时间 `lastTime` 用于线程回收判断\n",
    "  - 实际实现中需要处理线程退出条件和任务队列空的情况"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `threadFunc` 的修改 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程函数参数修改\n",
    "\n",
    "- 参数类型变更: 原线程函数 `ThreadFunc` 定义为 `std::function<void()>` 无参无返回值类型，现修改为 `std::function<void(int)>` 带整型参数类型。\n",
    "- 修改原因: 因为线程函数需要接收线程 `ID` 作为参数，用于后续线程管理。如字幕所述：\"大家现在这个参数还有一个什么 `MT` 类型呢，所以在这呢，同学们，你看。\"\n",
    "\n",
    "线程池数据结构变更\n",
    "\n",
    "- 容器类型变更: 从 `std::vector<std::unique_ptr<Thread>>` 改为 `std::unordered_map<int, std::unique_ptr<Thread>>`。\n",
    "- 变更原因:\n",
    "  - 线程管理需求: 需要在线程结束时通过线程 `ID` 快速定位并释放对应线程对象\n",
    "  - 映射关系建立: 建立线程 `ID` 到线程对象的映射关系，如字幕解释：\"我们没有办法去找这个线程对象，是不是我们做了一个线程 `ID` 到线程对象的这么一个映射？\"\n",
    "\n",
    "线程函数实现细节\n",
    "\n",
    "- `ID` 生成机制: 使用静态变量 `generateId_` 为每个线程生成唯一 `ID`\n",
    "- 线程回收逻辑:\n",
    "  - 在 `CACHED` 模式下，当线程空闲超过阈值时间（60 秒）且当前线程数超过初始数量时进行回收\n",
    "  - 通过线程 `ID` 从 `map` 中定位并删除对应线程对象，如字幕说明：\"然后在这里边你去删除的话，你是不是就可以通过这个 `ID` 找见 `map` 里边对应的线程对象，然后进行一个删除了？\"\n",
    "\n",
    "线程池启动流程\n",
    "\n",
    "- 线程创建:\n",
    "  - 使用 `std::make_unique<Thread>` 创建线程对象\n",
    "  - 通过 `std::bind` 绑定线程函数和参数\n",
    "- 线程管理:\n",
    "  - 使用 `emplace` 将线程 `ID` 和线程对象存入 `map`\n",
    "  - 更新当前线程数计数器 `curThreadSize_`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 线程池Cached模式设计实现三"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## submitTask"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 任务提交流程:\n",
    "  - 获取互斥锁保证线程安全\n",
    "  - 使用条件变量等待队列有空位，最长等待 `1` 秒\n",
    "  - 若超时仍未获得空位，返回失败结果\n",
    "  - 成功获取空位后将任务加入队列\n",
    "  - 通知等待线程有新任务到达\n",
    "- `Cached` 模式处理:\n",
    "  - 当任务数大于空闲线程数且当前线程数未达阈值时\n",
    "  - 创建新线程对象并存入线程 `map`\n",
    "  - 必须显式启动线程（关键易漏点）\n",
    "  - 更新线程计数器和空闲线程计数器\n",
    "- 线程计数优化建议:\n",
    "  - `curThreadSize_` 可用 `threads_.size()` 替代\n",
    "  - 但已实现的代码需保持各计数器同步更新\n",
    "  - 空闲线程计数器必须单独维护"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 线程函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 新线程创建细节:\n",
    "  - 使用 `std::bind` 绑定线程函数\n",
    "  - 线程 `ID` 作为 `map` 的 `key` 存储\n",
    "  - 创建后立即启动（关键步骤）\n",
    "  - 计数器更新顺序：先 `curThreadSize_` 后 `idleThreadSize_`\n",
    "- 重要成员变量:\n",
    "  - `threads_`: 使用 `unordered_map` 存储线程对象\n",
    "  - 双计数器设计：`curThreadSize_` 和 `idleThreadSize_`\n",
    "  - 任务队列使用标准 `queue` 容器\n",
    "  - 线程安全通过 `mutex` 和 `condition_variable` 实现\n",
    "- 线程清理要点:\n",
    "  - 从线程 `map` 中 `erase` 对应线程\n",
    "  - 注意处理迭代器失效问题\n",
    "  - 不需要手动递减 `curThreadSize_`（由容器 `size` 决定）\n",
    "  - 但需要更新空闲线程计数器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 线程池实现细节"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "任务提交与线程分配\n",
    "\n",
    "- 任务队列操作：\n",
    "  - 使用 `taskQue_.emplace(sp)` 将任务放入队列\n",
    "  - 任务计数器 `taskSize_` 递增\n",
    "  - 通过 `notEmpty_.notify_all()` 通知等待线程\n",
    "- `CACHED` 模式处理：\n",
    "  - 当满足三个条件时创建新线程：\n",
    "    - 当前模式为 `MODE_CACHED`\n",
    "    - 任务数量大于空闲线程数 `taskSize_ > idleThreadSize_`\n",
    "    - 当前线程数小于阈值 `curThreadSize_ < threadSizeThreshHold_`\n",
    "  - 新线程创建流程：\n",
    "    - 使用 `std::make_unique` 创建线程对象\n",
    "    - 通过 `threads_.emplace` 加入线程池\n",
    "    - 启动线程并更新计数器 `curThreadSize_++` 和 `idleThreadSize_++`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程 `ID` 管理\n",
    "\n",
    "- `ID` 生成机制：\n",
    "  - 使用线程库自动生成的 `ID` `ptr->getId()`\n",
    "  - 避免使用 `std::this_thread::get_id()` 获取线程 `ID`\n",
    "- 线程删除处理：\n",
    "  - 通过 `threads_.erase(threadid)` 移除线程对象\n",
    "  - 需要同步更新线程计数器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程回收机制\n",
    "\n",
    "- 回收条件判断：\n",
    "  - 空闲时间超过阈值 `THREAD_MAX_IDLE_TIME`（`60` 秒）\n",
    "  - 当前线程数大于初始线程数 `curThreadSize_ > initThreadSize_`\n",
    "- 回收执行流程：\n",
    "  - 使用条件变量 `wait_for` 进行超时检测\n",
    "  - 计算持续时间 `duration_cast<seconds>(now - lastTime)`\n",
    "  - 满足条件时执行线程删除和计数器更新"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池初始化\n",
    "\n",
    "- 初始化参数：\n",
    "  - 设置运行标志 `isPoolRunning_ = true`\n",
    "  - 记录初始线程数 `initThreadSize_`\n",
    "- 线程创建：\n",
    "  - 使用 `std::bind` 绑定线程函数 `threadFunc`\n",
    "  - 通过循环创建指定数量的线程对象\n",
    "  - 每个线程获取唯一 `ID` 并存入线程池"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "重要注意事项\n",
    "\n",
    "- 线程计数器同步：\n",
    "  - 删除线程时必须同步减少 `curThreadSize_`\n",
    "  - 空闲线程数 `idleThreadSize_` 需要对应调整\n",
    "- 调试信息：\n",
    "  - 建议添加线程创建/销毁的日志输出\n",
    "  - 使用标准库提供的线程 `ID` 进行标识\n",
    "- 资源管理：\n",
    "  - 确保线程对象被正确释放\n",
    "  - 注意条件变量通知时机的准确性"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 线程池应用案例"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池任务提交与执行机制\n",
    "\n",
    "- 工作模式设置：通过 `pool.setMode(PoolMode::MODE_CACHED)` 设置线程池为缓存模式，该模式下线程数量会根据任务量动态调整。\n",
    "- 线程启动：`pool.start(4)` 初始化 `4` 个工作线程，这是线程池的基础线程数量。\n",
    "- 任务提交：使用 `submitTask` 方法提交任务，示例中提交了计算从 `1` 到 `300000000` 的累加任务，分三个子任务完成。\n",
    "- 结果机制：\n",
    "  - 通过 `Result` 对象获取任务执行结果\n",
    "  - `get()` 方法返回 `Any` 类型，需使用 `cast_<T>()` 转换为具体类型（如 `uLong`）\n",
    "  - 注意任务对象和结果对象的生命周期关联\n",
    "- 任务设计：\n",
    "  - 继承自 `Task` 基类\n",
    "  - `run()` 方法返回 `Any` 类型，可表示任意返回值类型（`C++17` 特性）\n",
    "  - 示例中的 `MyTask` 实现大数累加计算，耗时约 `3` 秒\n",
    "\n",
    "线程池动态调整机制\n",
    "\n",
    "- 任务过载场景：\n",
    "  - 初始 `4` 个线程处理 `6` 个任务\n",
    "  - 每个任务耗时约 `3` 秒\n",
    "  - 前 `4` 个任务会占满初始线程\n",
    "- 动态线程创建：\n",
    "  - 缓存模式下，当 `taskSize_ > idleThreadSize_` 且 `curThreadSize_ < threadSizeThreshHold_` 时会创建新线程\n",
    "  - 后 `2` 个任务会触发创建 `2` 个新线程处理\n",
    "- 空闲线程回收：\n",
    "  - 线程空闲超过 `THREAD_MAX_IDLE_TIME`（示例中为 `1` 秒）会被回收\n",
    "  - 保证线程数量不低于初始数量 `initThreadSize_`\n",
    "  - 回收时会修改线程计数并从线程列表移除\n",
    "\n",
    "线程池任务处理流程\n",
    "\n",
    "- 任务分配：\n",
    "  - 新任务放入任务队列 `taskQue_`\n",
    "  - 通过 `notEmpty_.notify_all()` 通知空闲线程\n",
    "- 紧急任务处理：\n",
    "  - 缓存模式特别适合处理“小而快”的任务\n",
    "  - 根据任务数量和空闲线程数动态判断是否需要扩容\n",
    "- 线程创建细节：\n",
    "  - 使用 `std::make_unique` 创建线程对象\n",
    "  - 线程 `ID` 与线程对象通过 `map` 管理\n",
    "  - 启动后更新线程计数变量"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 线程池任务提交与线程管理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "任务提交机制\n",
    "\n",
    "- 任务队列限制：当任务队列满时，提交任务会阻塞最多 `1` 秒，超时则返回失败结果\n",
    "- 条件变量使用：通过 `notFull_` 和 `notEmpty_` 条件变量实现线程间通信\n",
    "- 失败处理：若 `1` 秒后队列仍满，输出错误信息并返回包含 `false` 的 `Result` 对象\n",
    "- 成功处理：任务入队后通过 `notEmpty_.notify_all()` 通知线程执行任务\n",
    "\n",
    "`CACHED` 模式特性\n",
    "\n",
    "- 动态线程创建：当初始线程（`4` 个）全部占用且仍有新任务时，会自动创建新线程\n",
    "- 任务分配验证：通过打印 `\"create new thread\"` 字符串确认线程创建行为\n",
    "- 预期行为：`4` 个初始线程处理 `4` 个任务，额外任务应触发新线程创建\n",
    "\n",
    "线程回收机制\n",
    "\n",
    "- 空闲时间阈值：线程空闲超过 `10` 秒（原 `60` 秒，为测试改为 `10` 秒）且超过初始线程数时会被回收\n",
    "- 回收条件判断：\n",
    "  - 使用 `wait_for` 检测超时状态\n",
    "  - 计算当前时间与上次执行时间的差值\n",
    "  - 比较差值是否超过 `THREAD_MAX_IDLE_TIME`\n",
    "- 回收操作：\n",
    "  - 从线程列表删除对应线程对象\n",
    "  - 更新当前线程数（`curThreadSize_`）和空闲线程数（`idleThreadSize_`）\n",
    "  - 打印线程退出信息\n",
    "\n",
    "测试案例验证\n",
    "\n",
    "- 任务设计：包含长时间运行任务（每个耗时约 `3` 秒）\n",
    "- 预期结果：\n",
    "  - 初始 `4` 个线程处理前 `4` 个任务\n",
    "  - 剩余 `2` 个任务应触发创建 `2` 个新线程\n",
    "  - 任务完成后，额外创建的 `2` 个线程在空闲 `10` 秒后应被回收\n",
    "- 线程数量保持：最终线程池应恢复到初始的 `4` 个线程状态\n",
    "\n",
    "`Result` 机制实现\n",
    "\n",
    "- 结果获取：通过 `get().cast_<uLong>()` 将 `Any` 类型转换为具体类型\n",
    "- 对象生命周期：\n",
    "  - 任务执行完成后 `task` 对象会被析构\n",
    "  - 依赖于 `task` 对象的 `Result` 对象也随之失效\n",
    "- 类型安全：使用模板机制确保类型转换的安全性"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 线程池任务提交问题分析与解决"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`CACHED` 模式下的异常现象\n",
    "\n",
    "- 异常现象：在 `CACHED` 模式下线程池出现任务提交失败的情况，控制台输出 `\"task queue is full, submit task fail\"` 提示信息\n",
    "- 问题定位：该现象与 `CACHED` 模式的设计预期不符，正常情况下应能动态创建线程处理任务\n",
    "\n",
    "任务队列容量限制分析\n",
    "\n",
    "- 阈值设置：代码中默认设置任务队列最大容量 `TASK_MAX_THRESHHOLD = 4`，这是导致提交失败的根本原因\n",
    "- 不合理设计：实际开发中任务队列容量不应设置如此小的值，参考开源实现通常使用 `INT32_MAX` 等较大值\n",
    "- 验证方法：通过打印日志可见当提交第 `5` 个任务时开始出现失败提示\n",
    "\n",
    "任务提交机制实现细节\n",
    "\n",
    "- 等待策略：使用 `wait_for` 实现带超时的条件等待，最长阻塞 `1` 秒后判断队列是否仍有空间\n",
    "- 失败处理：当等待超时且队列仍满时，返回包含失败标志的 `Result` 对象\n",
    "- 线程安全：通过 `unique_lock` 保证任务队列操作的线程安全性\n",
    "\n",
    "开发问题解决建议\n",
    "\n",
    "- 调试态度：遇到问题应保持冷静，通过日志和代码分析定位根本原因\n",
    "- 独立思考：避免过度依赖老师，培养独立解决问题的能力\n",
    "- 经验积累：通过解决实际问题逐步提升调试技能和工程能力\n",
    "- 代码规范：合理设置常量阈值，避免出现明显不合理的硬编码值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 运行结果展示 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程创建与退出\n",
    "\n",
    "- 线程创建验证：系统成功创建了两个线程（线程 `ID`: `18328` 和 `16004`），符合预期设计\n",
    "- 线程生命周期：`10` 秒后观察到这两个线程正常退出，通过日志 `\"threadid: 18328 exit!\"` 和 `\"threadid: 16004 exit!\"` 确认\n",
    "- 输出特性：不同线程的输出没有强制互关系，`create new thread` 信息由用户调用线程输出，而获取任务日志由线程池内部线程输出\n",
    "\n",
    "线程任务获取情况\n",
    "\n",
    "- 多线程并发：系统共创建 `6` 个线程（包括主线程），所有线程都在尝试获取任务\n",
    "- 异常现象：虽然线程持续尝试获取任务（如 `tid:9008`、`6860` 等），但日志中未出现 `\"获取任务成功\"` 的记录\n",
    "- 线程行为：线程在任务队列为空时会进入等待状态，通过条件变量 `notEmpty_` 进行通知机制\n",
    "\n",
    "任务未成功获取问题\n",
    "\n",
    "- 问题定位：线程函数中虽然打印了 `\"尝试获取任务\"`，但缺少成功获取后的确认日志\n",
    "- 预期行为：正常情况应在获取任务成功后输出类似 `\"tid:[线程ID]获取任务成功\"` 的日志\n",
    "- 矛盾点：尽管提交了多个任务（如 `MyTask(1,100000000)` 等），但线程似乎未能成功消费这些任务\n",
    "\n",
    "线程函数逻辑分析\n",
    "\n",
    "- 基本流程：\n",
    "  - 获取互斥锁保护任务队列\n",
    "  - 检查线程池模式（`MODE_CACHED`）\n",
    "  - 根据任务队列状态决定等待或执行任务\n",
    "- 缓存模式处理：当 `poolMode_ == PoolMode::MODE_CACHED` 时，会检查线程空闲时间，超过 `THREAD_MAX_IDLE_TIME`（`60` 秒）且当前线程数大于初始值时回收线程\n",
    "\n",
    "任务队列与线程唤醒条件\n",
    "\n",
    "- 等待条件：原代码使用 `while (taskQue_.size() > 0)` 作为等待条件存在逻辑错误\n",
    "- 正确逻辑：应该当任务队列为空时才等待，有任务时应立即消费\n",
    "- 条件变量机制：`notEmpty_.wait_for(lock, std::chrono::seconds(1))` 实现超时返回，用于线程回收判断\n",
    "\n",
    "代码错误识别与修正\n",
    "\n",
    "- 错误定位：条件判断 `while (taskQue_.size() > 0)` 与 `notEmpty_.wait_for` 的组合使用不当\n",
    "- 问题本质：当任务队列有任务时线程仍在等待，违背“有任务立即消费”的设计原则\n",
    "- 修正方案：应将条件改为 `while (taskQue_.size() == 0)`，确保队列不空时立即处理任务\n",
    "- 回收机制：线程空闲超时后执行资源回收，包括：\n",
    "  - 修改线程计数变量（`curThreadSize_--`, `idleThreadSize_--`）\n",
    "  - 从线程列表删除对象（`threads_.erase(threadid)`）\n",
    "  - 输出退出日志后返回（`threadFunc` 函数结束）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 任务提交失败与任务获取失败问题"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池的工作模式与任务队列\n",
    "\n",
    "- 任务提交失败机制：当任务队列满时，提交任务会等待 `1` 秒，若仍无法提交则返回失败结果。通过条件变量 `notFull_.wait_for` 实现超时控制。\n",
    "- 任务队列阈值设置：通过 `setTaskQueMaxThreshHold` 方法设置任务队列上限，当 `taskQue_.size() >= taskQueMaxThreshHold_` 时触发提交限制。\n",
    "- 动态线程创建：在 `cached` 模式下，当任务数量超过空闲线程数量时，会自动创建新线程处理紧急的小而快任务。\n",
    "- 关键参数：\n",
    "  - `TASK_MAX_THRESHHOLD = INT32_MAX`：任务队列最大阈值\n",
    "  - `THREAD_MAX_THRESHHOLD = 10`：线程最大数量限制\n",
    "  - `THREAD_MAX_IDLE_TIME = 10`：线程最大空闲时间（秒）\n",
    "\n",
    "线程池中的线程回收机制 \n",
    "\n",
    "- 回收条件：\n",
    "  - 当前为 `cached` 模式\n",
    "  - 线程空闲时间超过 `THREAD_MAX_IDLE_TIME`（`10` 秒）\n",
    "  - 当前线程数大于初始线程数（`curThreadSize_ > initThreadSize_`）\n",
    "- 回收过程：\n",
    "  - 从线程列表 `threads_` 中移除对应线程\n",
    "  - 减少当前线程数 `curThreadSize_--`\n",
    "  - 减少空闲线程数 `idleThreadSize_--`\n",
    "- 线程生命周期：线程函数 `threadFunc` 通过返回结束线程\n",
    "- 任务获取机制：使用 `notEmpty_.wait_for` 等待任务，超时后检查是否需要回收线程\n",
    "- 执行记录：每个线程执行任务时会打印线程 `ID` 和任务状态，如 `\"tid:12256尝试获取任务...\"`\n",
    "\n",
    "线程池对象的作用域与资源回收\n",
    "\n",
    "- 析构问题：线程池对象析构时，线程仍在等待条件变量，导致无法正常回收\n",
    "- 解决方案：需要实现线程池的优雅关闭机制，包括：\n",
    "  - 设置关闭标志位\n",
    "  - 唤醒所有等待线程\n",
    "  - 等待所有线程结束\n",
    "- 典型场景：示例中提交 `6` 个任务，初始 `4` 个线程动态扩展至 `6` 个，最终回收至 `4` 个\n",
    "- 线程行为验证：通过输出日志确认每个线程成功获取任务，如 `\"tid:2680获取任务成功...\"`\n",
    "- 结果合并：使用 `Master-Slave` 模型，主线程分解任务并合并结果，输出总和 `45000000150000000`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 线程池资源回收问题 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 核心问题: `ThreadPool` 对象析构后如何回收所有线程资源\n",
    "- 关键点:\n",
    "  - 需要确保线程池中所有线程都能正确结束\n",
    "  - 除了线程资源外，还需考虑其他需要释放的资源\n",
    "  - 解决方案应实现在 `ThreadPool` 的析构函数中"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `CACHED` 模式线程回收机制\n",
    "\n",
    "- 回收条件:\n",
    "  - 线程空闲时间超过 `60` 秒（`THREAD_MAX_IDLE_TIME`）\n",
    "  - 当前线程数大于初始线程数（`curThreadSize_ > initThreadSize_`）\n",
    "- 实现方法:\n",
    "  - 使用条件变量 `wait_for` 进行超时检测\n",
    "  - 计算时间差：`dur = std::chrono::duration_cast(now - lastTime)`\n",
    "  - 线程回收步骤：\n",
    "    - 修改线程计数变量（`curThreadSize_--`）\n",
    "    - 从线程列表容器中删除对应线程（`threads_.erase(threadid)`）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 问题解决能力培养"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 成长关键:\n",
    "  - 遇到问题是能力提升的重要契机\n",
    "  - 通过解决问题可以重组和强化知识结构\n",
    "- 职场价值:\n",
    "  - 技术大佬的核心竞争力在于解决问题的能力\n",
    "  - 解决问题的能力是职场中的关键竞争优势\n",
    "  - 快速定位和解决问题的能力比单纯编码能力更重要"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 线程池实现细节"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 线程创建:\n",
    "  - 使用 `std::make_unique` 创建线程对象\n",
    "  - 线程函数绑定：`std::bind(&ThreadPool::threadFunc, this, std::placeholders::_1)`\n",
    "- 线程管理:\n",
    "  - 线程 `ID` 与线程对象的映射存储（`threads_.emplace`）\n",
    "  - 线程状态跟踪：\n",
    "    - 当前线程数（`curThreadSize_`）\n",
    "    - 空闲线程数（`idleThreadSize_`）\n",
    "- 任务处理循环:\n",
    "  - 使用无限循环持续获取任务（`for(;;)`）\n",
    "  - 通过共享指针管理任务对象（`std::shared_ptr<Task>`）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 线程函数与 `submitTask` 功能详解"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "任务提交与线程创建机制\n",
    "\n",
    "- 任务入队流程：\n",
    "  - 当任务队列有空余时，通过 `taskQue_.emplace(sp)` 将任务放入队列\n",
    "  - 任务计数器 `taskSize_` 自增\n",
    "  - 使用 `notEmpty_.notify_all()` 通知等待线程有新任务到达\n",
    "- `CACHED` 模式处理：\n",
    "  - 适用于小而快的紧急任务场景\n",
    "  - 当满足 `taskSize_ > idleThreadSize_` 且 `curThreadSize_ < threadSizeThreshHold_` 时创建新线程\n",
    "  - 新线程创建后需要更新 `curThreadSize_` 和 `idleThreadSize_` 计数\n",
    "\n",
    "线程回收机制\n",
    "\n",
    "- 超时检测：\n",
    "  - 使用 `notEmpty_.wait_for` 设置 `1` 秒超时检测\n",
    "  - 通过高精度时钟计算线程空闲时间 `dur.count()`\n",
    "- 回收条件：\n",
    "  - 空闲时间超过 `THREAD_MAX_IDLE_TIME`（`10` 秒）\n",
    "  - 当前线程数大于初始线程数 `initThreadSize_`\n",
    "- 回收操作：\n",
    "  - 从线程列表 `threads_` 中删除对应线程\n",
    "  - 同步更新 `curThreadSize_` 和 `idleThreadSize_` 计数\n",
    "\n",
    "线程池配置参数\n",
    "\n",
    "- 关键阈值：\n",
    "  - `TASK_MAX_THRESHHOLD = INT32_MAX`（任务队列上限）\n",
    "  - `THREAD_MAX_THRESHHOLD = 10`（线程数上限）\n",
    "  - `THREAD_MAX_IDLE_TIME = 10`（秒，线程最大空闲时间）\n",
    "- 配置建议：\n",
    "  - 线程数量应与 `CPU` 核数匹配为最佳\n",
    "  - 对于耗时任务（如文件传输）可适当增加线程数\n",
    "  - 不同服务器配置（`8G` vs `64G` 内存）应设置不同的线程上限\n",
    "  - 推荐设置 `100-1024` 个线程为上限，避免直接使用 `INT32_MAX`\n",
    "\n",
    "`CACHED` 模式线程管理\n",
    "\n",
    "- 线程创建：\n",
    "  - 使用 `std::make_unique` 创建线程对象\n",
    "  - 通过 `threads_.emplace` 将线程加入管理容器\n",
    "  - 调用 `start()` 方法启动线程执行\n",
    "- 资源回收：\n",
    "  - 超过初始线程数的多余线程会被回收\n",
    "  - 回收时需要处理线程对象与线程函数的映射关系\n",
    "  - 输出线程退出日志便于调试\n",
    "\n",
    "条件变量使用要点\n",
    "\n",
    "- 锁保护：\n",
    "  - 使用 `std::unique_lock` 保护任务队列操作\n",
    "  - 通过 `taskQueMtx_` 实现线程安全访问\n",
    "- 双重检查：\n",
    "  - 先检查任务队列是否为空 `taskQue_.size() == 0`\n",
    "  - 再检查是否满足超时条件 `dur.count() >= THREAD_MAX_IDLE_TIME`\n",
    "- 调试输出：\n",
    "  - 打印线程 `ID` `std::this_thread::get_id()` 辅助调试\n",
    "  - 输出线程退出信息确认回收流程"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 代码编写与测试 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程池核心逻辑实现\n",
    "\n",
    "- 锁机制实现：使用 `std::unique_lock<std::mutex>` 获取任务队列锁 `taskQueMtx_`，确保线程安全\n",
    "- 线程回收策略：在 `cached` 模式下，当线程空闲时间超过 `60` 秒且数量超过初始线程数 `initThreadSize_` 时进行回收\n",
    "- 调试输出：通过 `std::this_thread::get_id()` 打印线程 `ID`，显示 `\"尝试获取任务...\"` 和 `\"获取任务成功...\"` 等状态信息\n",
    "\n",
    "线程池参数配置\n",
    "\n",
    "- 任务队列阈值：`TASK_MAX_THRESHHOLD = INT32_MAX`（最大任务数量）\n",
    "- 线程数量限制：`THREAD_MAX_THRESHHOLD = 1024`（最大线程数）\n",
    "- 空闲超时时间：`THREAD_MAX_IDLE_TIME = 60`（单位：秒），超过此时长的空闲线程将被回收\n",
    "\n",
    "代码测试要点\n",
    "\n",
    "- 测试必要性：必须验证测试结果与预期相符，确保代码逻辑正确表达设计意图\n",
    "- 回收机制验证：重点测试线程在空闲 `60` 秒后是否能正确被回收\n",
    "- 模式切换测试：通过 `setMode(PoolMode mode)` 测试不同工作模式下的线程行为\n",
    "\n",
    "线程池析构问题\n",
    "\n",
    "- 核心问题：`ThreadPool` 对象析构时如何确保所有线程资源被正确回收\n",
    "- 使用示例：\n",
    "- 任务提交：通过 `submitTask` 方法提交任务，使用 `std::make_shared` 创建任务对象\n",
    "- 结果机制：需要设计合理的 `Result` 机制来处理任务执行结果"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "name": "C++17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
